using System;
using System.Collections.Generic;
using System.Linq;
using HCore.Extensions;
using HCore.Unity.Core;
using HCore.Unity.Extensions;
using JetBrains.Annotations;
using Session;
using UnityEngine;

namespace Game.Board
{
    [UsedImplicitly]
    [HCore.IOC.Context.Stereotype.Component]
    public class BoardService : SessionHCoreMonoBehaviour
    {
        #region 排序 Tile

        /// <summary>
        ///     Tile 排序时的移动速度
        /// </summary>
        private const float _TILE_SORT_MOVE_DURATION = 0.3f;

        /// <summary>
        ///     颜色差值
        /// </summary>
        private const float _COLOR_DIFF = 0.2f;

        /// <summary>
        ///     根据颜色差值找到的像素占比
        /// </summary>
        private const float _COLOR_RATE = 0.2f;

        /// <summary>
        ///     按颜色进行随机放置
        /// </summary>
        /// <param name="placementWorldPosition"></param>
        /// <param name="targetColor"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void SortSimilarColorTiles(Vector3 placementWorldPosition, Color targetColor)
        {
            if (Session?.Board == null) return;
            Debug.Log($"按颜色进行随机放置。 WorldPosition: {placementWorldPosition}, TargetColor: {targetColor}");
            var tiles = Session.Board.ControlTiles.GetRandoms()
                .Select(vec => Session.Board.Tiles[vec.x, vec.y])
                .ToList(); // 需要找出所有受控的 Tile

            // 在鼠标周边形成一个矩形，把找到颜色相关的Tile移动到这个矩形中
            var rect = new Rect(placementWorldPosition.x, placementWorldPosition.y - 1000, 1000, 1000);

            var tileMoveData = new List<TileMoveData>();
            foreach (var tile in tiles)
            {
                // 过滤掉 (0,0,0,0) 的颜色 
                var colors = tile.FinalCutTexture.GetPixels().Where(color => !color.Equals(Color.clear)).ToArray();
                // 计算和目标颜色的加权平均差异（0->1。值越小，越近似。0：相等）
                var average = colors.Average(color => GameUtils.DifferenceColor(color, targetColor) < _COLOR_DIFF ? 1 : 0);
                if (average > _COLOR_RATE) tileMoveData.Add(new TileMoveData(tile.Index, rect.RandomPosition(), _TILE_SORT_MOVE_DURATION, 0.002f));
            }

            PublishEvent(new TileMoveEvent(tileMoveData));
        }

        /// <summary>
        ///     把拼图四边的 Tile 找出来，并随机放置到指定地点的矩形框中
        /// </summary>
        /// <param name="placementWorldPosition"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void SortSideTiles(Vector3 placementWorldPosition)
        {
            if (Session?.Board == null) return;

            Debug.Log("把拼图四边的 Tile 找出来，并随机放置到指定地点的矩形框中");
            var board = Session.Board;
            var numTileX = board.NumTileX;
            var numTileY = board.NumTileY;
            var tileSize = board.TileSize;

            // 需要找出四边且受控的 Tile
            var controlTiles = board.ControlTiles.GetRandoms()
                .FindAll(vec => vec.x == 0 || vec.y == 0 || vec.x == numTileX - 1 || vec.y == numTileY - 1)
                .Select(vec => board.Tiles[vec.x, vec.y])
                .ToList();

            var subSize = (int)Math.Sqrt(controlTiles.Count);
            var tiles = controlTiles.ExpandTo2DArray(subSize);
            var tileMoveData = new List<TileMoveData>();
            for (var y = 0; y < tiles.Length; y++)
            {
                var cols = tiles[y];
                for (var x = 0; x < cols.Length; x++)
                {
                    var tile = cols[x];
                    var endPosition = new Vector2(placementWorldPosition.x + (x + x * 0.7f) * tileSize, placementWorldPosition.y - (y + y * 0.7f) * tileSize);
                    tileMoveData.Add(new TileMoveData(tile.Index, endPosition, _TILE_SORT_MOVE_DURATION, 0.005f));
                }
            }

            PublishEvent(new TileMoveEvent(tileMoveData));
        }

        /// <summary>
        ///     随机打乱拼图块，会把所有的 Tile 打乱顺序然后，随机放置到 Board 的周围
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        public void SortCenterRandomTiles()
        {
            if (Session?.Board == null) return;
            Debug.Log("随机打乱拼图块，会把所有的 Tile 打乱顺序然后，随机放置到 Board 的周围");

            ///// 这里先以左下角为计算点。完成后，直接移动中心点的偏移量即可（为什么这样，历史遗留问题。之前 Sprite 起始点在左下角，之后改为了中心点。所以才有后面这个移动的逻辑）
            ///// 左右两边高度为 Board 高度(width)，宽度为 Board 短边长度 + Padding = (minEdge + padding); 
            ///// 上下两边高度为 Board 短边一半，宽度为 Padding + 短边长 + Board宽度 + 短边长 + Padding;
            // 如下：
            // ===
            // -x-
            // ===

            var board = Session.Board;
            var boardPos = transform.position;

            var height = board.Height;
            var width = board.Width;
            var minEdge = Math.Min(height, width);
            var padding = board.TilePadding;
            var halfMinEdge = minEdge / 2;

            var halfBoardWidth = width / 2;
            var halfBoardHeight = height / 2;

            // 隔离带
            var isolation = board.TileSize + padding;

            // var minEdge = Mathf.Min(effectiveTextureHeight, effectiveTextureWidth);
            // var padding = Mathf.Min(tilePadding * 4, tileSize + tilePadding);

            var rects = new Rect[6];
            // 上
            rects[0] = new Rect(
                new Vector2(boardPos.x - padding - minEdge, boardPos.y + height + padding + isolation), // √
                new Vector2(padding + minEdge + width + minEdge + padding, halfMinEdge)); // √
            rects[0].center = new Vector2(rects[0].center.x - halfBoardWidth, rects[0].center.y - halfBoardHeight); // √
            // 下
            rects[1] = new Rect(
                new Vector2(boardPos.x - padding - minEdge, boardPos.y - halfMinEdge - isolation), // √
                new Vector2(padding + minEdge + width + minEdge + padding, halfMinEdge)); // √
            rects[1].center = new Vector2(rects[1].center.x - halfBoardWidth, rects[1].center.y - halfBoardHeight); // √


            // 左
            rects[2] = new Rect(
                new Vector2(boardPos.x - padding - minEdge - isolation, boardPos.y), // √
                new Vector2(minEdge + padding, height)); // √
            rects[2].center = new Vector2(rects[2].center.x - halfBoardWidth, rects[2].center.y - halfBoardHeight); // √
            // 右
            rects[3] = new Rect(
                new Vector2(boardPos.x + width + padding + isolation, boardPos.y), // √
                new Vector2(minEdge + padding, height)); // √
            rects[3].center = new Vector2(rects[3].center.x - halfBoardWidth, rects[3].center.y - halfBoardHeight); // √

            // 因为上下两个区域比左右两个区域大一倍，所以，需要重复一下，平衡 Tile 在每个区域的数量
            // 上2
            rects[4] = rects[0];
            // 下2
            rects[5] = rects[1];


            var tiles = board.ControlTiles.Select(tileVec => Session.Board.Tiles[tileVec.x, tileVec.y]).ToArray();
            var tileMoveData = new List<TileMoveData>();
            var delaySecond = 1.5f / tiles.Length;
            foreach (var tile in tiles)
            {
                var endPosition = rects.GetRandom().RandomPosition();
                tileMoveData.Add(new TileMoveData(tile.Index, endPosition, _TILE_SORT_MOVE_DURATION, delaySecond));
            }

            PublishEvent(new TileMoveEvent(tileMoveData));
        }

        /// <summary>
        ///     按照九宫格把 Tile 分组分九宫格进行随机放置
        /// </summary>
        /// <param name="placementWorldPosition"></param>
        public void SortNineGridTiles(Vector3 placementWorldPosition)
        {
            if (Session?.Board == null) return;

            Debug.Log("按照九宫格把 Tile 分组分九宫格进行随机放置");

            var board = Session.Board;
            var numTileX = board.NumTileX;
            var numTileY = board.NumTileY;
            var tileSize = board.TileSize;

            var tiles = Session.Board.ControlTiles.GetRandoms()
                .Select(vec => Session.Board.Tiles[vec.x, vec.y])
                .ToList(); // 需要找出所有受控的 Tile

            // 算出九宫格每个各自的大小(其实，就是算出九宫格两横两纵线的坐标)，相当于各自应该放多少个拼图块
            var xSize = numTileX % 3 == 0 ? numTileX / 3 : numTileX / 3 + 1;
            var ySize = numTileY % 3 == 0 ? numTileY / 3 : numTileY / 3 + 1;

            var tileGroup = new List<Tile.Tile>[3][];
            for (var index = 0; index < 3; index++) tileGroup[index] = new List<Tile.Tile>[3];

            foreach (var tile in tiles)
            {
                var x = tile.Index.x;
                var y = tile.Index.y;

                // 最左边一列
                if (x < xSize)
                {
                    // 最上边一列
                    if (y < ySize)
                    {
                        tileGroup[0][2] ??= new List<Tile.Tile>();
                        tileGroup[0][2].Add(tile);
                    }
                    // 中间列 
                    else if (ySize <= y && y < 2 * ySize)
                    {
                        tileGroup[0][1] ??= new List<Tile.Tile>();
                        tileGroup[0][1].Add(tile);
                    }
                    // 最下边列
                    else // if (2 * cellCount <= y)
                    {
                        tileGroup[0][0] ??= new List<Tile.Tile>();
                        tileGroup[0][0].Add(tile);
                    }
                }
                // 中间列 
                else if (xSize <= x && x < 2 * xSize)
                {
                    // 最上边一列
                    if (y < ySize)
                    {
                        tileGroup[1][2] ??= new List<Tile.Tile>();
                        tileGroup[1][2].Add(tile);
                    }
                    // 中间列 
                    else if (ySize <= y && y < 2 * ySize)
                    {
                        tileGroup[1][1] ??= new List<Tile.Tile>();
                        tileGroup[1][1].Add(tile);
                    }
                    // 最下边列
                    else //if (2 * cellCount <= y)
                    {
                        tileGroup[1][0] ??= new List<Tile.Tile>();
                        tileGroup[1][0].Add(tile);
                    }
                }
                // 最右边列
                else if (2 * xSize <= x)
                {
                    // 最上边一列
                    if (y < ySize)
                    {
                        tileGroup[2][2] ??= new List<Tile.Tile>();
                        tileGroup[2][2].Add(tile);
                    }
                    // 中间列 
                    else if (ySize <= y && y < 2 * ySize)
                    {
                        tileGroup[2][1] ??= new List<Tile.Tile>();
                        tileGroup[2][1].Add(tile);
                    }
                    // 最下边列
                    else // if (2 * cellCount <= y)
                    {
                        tileGroup[2][0] ??= new List<Tile.Tile>();
                        tileGroup[2][0].Add(tile);
                    }
                }
            }

            // 定义九宫格宽高
            var rectWidth = (numTileX * tileSize + tileSize * 3) / 2;
            var rectHeight = (numTileY * tileSize + tileSize * 3) / 2;

            // 循环分配拼图块进入九宫格
            var tileMoveData = new List<TileMoveData>();
            for (var x = 0; x < 3; x++)
            for (var y = 0; y < 3; y++)
            {
                var list = tileGroup[x][y];
                if (list == null || list.Count == 0) continue;

                // 构建九宫格格子
                var rectX = placementWorldPosition.x + x * rectWidth;
                var rectY = placementWorldPosition.y - y * rectHeight;
                var rect = new Rect(rectX, rectY, rectWidth, rectHeight);

                foreach (var tile in list)
                {
                    var endPosition = rect.RandomPosition();
                    tileMoveData.Add(new TileMoveData(tile.Index, endPosition, _TILE_SORT_MOVE_DURATION, 0.005f));
                }
            }

            PublishEvent(new TileMoveEvent(tileMoveData));
        }

        #endregion
    }
}